package iot.core.data.mapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import iot.core.data.*;
import iot.core.exception.MyException;
import iot.core.manager.htcls.HTClsManager;
import iot.core.manager.id.HTIDManager;
import iot.core.springboot.MyThreadLocal;
import iot.core.util.StreamUtil;

import java.util.Date;


public interface MyBaseMapper<T> extends BaseMapper<T> {
    default void  beforeInsert(T entity) throws  Exception{
        if(entity instanceof BaseEntity be){
            if(ObjectUtils.isEmpty(be.getId())||be.getId().toString().equals("0")){
                be.setId(HTIDManager.getInstance().nextLong());
            }
        }
        var su=MyThreadLocal.get().getSu();
        var mcls=HTClsManager.getInstance().findByFullName(entity.getClass().getName() );
        for(var f:mcls.getFields()){
            var EName=f.getEName();
            var FV=f.getField().get(entity);
            switch (EName){
                case "Crt_DT":
                case "Edt_DT":
                {
                    if(ObjectUtils.isEmpty(FV)){
                        f.getField().set(entity,new Date() );
                    }
                }
                break;
                case "Crt_UId":
                case "Edt_UId":
                {
                    if(ObjectUtils.isEmpty(FV)||FV.toString().equals("0")){
                        f.getField().set(entity,su.getCrt_UId() );
                    }
                }
                break;
                case "Crt_DId":
                {
                    if(ObjectUtils.isEmpty(FV)||FV.toString().equals("0")){
                        f.getField().set(entity,su.getCrt_DId() );
                    }
                }
                break;
                case "GId":
                {
                    if(ObjectUtils.isEmpty(FV)|| FV.toString().equals("")){
                        f.getField().set(entity,HTIDManager.getInstance().nextGuidStr()  );
                    }
                }
                default:
                {
                    switch (f.getLX()){
                        case "java.lang.String":
                        {
                            HTClsManager.getInstance().dealStrNullAndTrim(entity,f.getField() );
                        }
                        break;
                    }
                }
                break;
            }

        }
    }

    default void  beforeUpdate(T entity) throws  Exception{
        var su=MyThreadLocal.get().getSu();
        var mcls=HTClsManager.getInstance().findByFullName(entity.getClass().getName() );
        for(var f:mcls.getFields()){
            var EName=f.getEName();
            switch (EName)
            {
                case "Edt_UId":
                {
                    f.getField().set(entity,su.getCrt_UId() );
                }
                break;
                case "Edt_DT":
                {
                    f.getField().set(entity,new Date() );
                }
                break;
                default:
                {
                    switch (f.getLX()){
                        case "java.lang.String":
                        {
                            HTClsManager.getInstance().dealStrNullAndTrim(entity,f.getField() );
                        }
                        break;
                    }
                }
                break;
            }

        }
    }
    default   int insert(T entity,boolean autoField ){
        var r=0;
        if(!autoField){
            r= insert(entity);
        }else{
            try {
                beforeInsert(entity);
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
            r= insert(entity);
        }
        if(r>0){
            MyThreadLocal.get().setInserted(entity);
            MyThreadLocal.get().getInserteds().add(entity);
        }
        return r;
    }
    default   int updateById(T entity,boolean autoField ){
        var r=0;
        if(!autoField){
            r= updateById(entity);
        }else{
            try {
                beforeUpdate(entity);
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
            r= updateById(entity);
        }
        if(r>0){
            MyThreadLocal.get().setInserted(entity);
            MyThreadLocal.get().getInserteds().add(entity);
        }
        return r;
    }
    default   int deleteById(T entity,boolean autoField ){
        var r=0;
        if(!autoField){
            r= deleteById(entity);
        }else{
            var bHaveDelete=HTClsManager.getInstance().hasField(entity,"Deleted");
            if(bHaveDelete){

                HTClsManager.getInstance().setFieldV(entity,"Deleted",true);
                r= updateById(entity,autoField);
            }
           else{
                r= deleteById(entity);
            }
        }
        if(r>0){
            MyThreadLocal.get().setDeleted(entity);
            MyThreadLocal.get().getDeleteds().add(entity);
        }
        return r;
    }
    default boolean hasField(String fieldName){
        var clszz=ReflectionKit.getSuperClassGenericType(this.getClass(),MyBaseMapper.class,0);
        var mcls=HTClsManager.getInstance().findByFullName(clszz.getName() );
        if(mcls==null){
            return false;
        }
        var op=mcls.getFields().stream().filter(a->a.getEName().equals(fieldName))
                .findFirst();
        return op.isPresent();
    }

    default QueryWrapper<T> getQueryWrapper( ){
        var qw= new QueryWrapper<T>();
        var clszz=ReflectionKit.getSuperClassGenericType(this.getClass(),MyBaseMapper.class,0);
        var p=(BaseMapper<T> )this;
        if(hasField("Deleted")){
           qw.eq("Deleted",false);
        }
        return qw;

    }

    default <U> void entityToDto(T src, U dst)  {
//        final Map<String, Object> aProps = BeanUtils.describe(a);
//        final Map<String, Object> bProps = BeanUtils.describe(b);
//        aProps.keySet().retainAll(bProps.keySet());
//        for (Entry<String, Object> entry : aProps.entrySet()) {
//            BeanUtils.setProperty(b,entry.getKey(), entry.getValue());
//        }
        if (src == null || dst == null) {
            throw new MyException("不支持的对象");
        }
        var msrccls = HTClsManager.getInstance().findByFullName(src.getClass().getName());
        if (msrccls == null) {
            throw new MyException("不支持的对象");
        }
        var mdstcls = HTClsManager.getInstance().findByFullName(dst.getClass().getName());
        if (mdstcls == null) {
            throw new MyException("不支持的对象");
        }
        {
            var id=((BaseEntity)src).getId();
            if(dst instanceof BaseDto dst1){
                dst1.setId(id);
            }
            if(dst instanceof BaseEntity dst2){
                dst2.setId(id);
            }
        }
        for (var pdst : mdstcls.getFields()) {
            try{
                var psrc = StreamUtil.get(msrccls.getFields(), a -> a.getEName().equals(pdst.getEName()));
                if (psrc == null) {
                    continue;
                }
                if ("PWD".equals(pdst.getEName()) || "CZPWD".equals(pdst.getEName())) {
                    continue;
                }
                var vsrc = psrc.getField().get(src);
                if (vsrc == null) {
                    continue;//null 强制跳过
                }

                pdst.getField().set(dst, vsrc);
            }
            catch (Exception ex){
                ex.printStackTrace();
            }

        }
    }
    default <U> void dtoToEntity(  U src,T dst)  {
        if (src == null|| dst==null)
        {
            throw new MyException("不支持的对象");
        }
        var msrccls = HTClsManager.getInstance().findByFullName(src.getClass().getName());
        if(msrccls == null)
        {
            throw new MyException("不支持的对象");
        }
        var mdstcls = HTClsManager.getInstance().findByFullName(dst.getClass().getName());
        if (mdstcls == null)
        {
            throw new MyException("不支持的对象");
        }

        {
            if(src instanceof BaseDto src1){
                if( dst instanceof  BaseEntity dst1){
                    dst1.setId(src1.getId() );
                }
            }

        }

        for (var pdst : mdstcls.getFields()) {
            try {
                var psrc = StreamUtil.get(msrccls.getFields(), a -> a.getEName().equals(pdst.getEName()));
                if (psrc == null) {
                    continue;
                }
                if ("Crt_DT".equals(pdst.getEName()) || "Crt_UId".equals(pdst.getEName())|| "Crt_DId".equals(pdst.getEName())) {
                    continue;
                }
                //插入 、修改时间不能更新
                if ("Edt_DT".equals(pdst.getEName()) || "Edt_UId".equals(pdst.getEName())  ) {
                    continue;
                }

                if ("PWD".equals(pdst.getEName()) || "CZPWD".equals(pdst.getEName())) {
                    continue;
                }

                var vsrc = psrc.getField().get(src);
                if (vsrc == null&&!psrc.isIsNullable()) {
                    continue;//null 强制跳过
                }
                if (pdst.getEName().toString().equals("id"))
                {
                    if (vsrc.toString()=="0")
                    {
                        vsrc = HTIDManager.getInstance().nextLong() ;
                    }
                }
                pdst.getField().set(dst, vsrc);
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }

    }

    default PageData<T>  page(QueryWrapper<T>  qw, BasePageQto qm){
        var pg=new Page<T>();
        pg.setSize(qm.getPageSize());
        pg.setCurrent(qm.getPage() );
        var pgr=selectPage(pg,qw);
        var r=new PageData<T>();
        r.setData(pgr.getRecords());
        r.setTotal(pgr.getTotal() );
        return r;
    }
    default Long max(QueryWrapper<T>  qw,String filed){
        qw.select(String.format( "ifnull(MAX(%s),0) AS SortNo",filed) );
        var l=  this.selectMaps(qw);
        var SortNo = l.size()==0 ? 0L : Long.valueOf(String.valueOf(l.get(0).get("SortNo")));
        return  SortNo;
    }

    default T getById(Long Id){
        return  selectById(Id);
    }
    default T getById(BaseQto mm){
        return getById(mm.getId() );
    }

}
